package com.ruoyi.web.controller.system;

import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.ExamPaperAnswerObject;
import com.ruoyi.system.domain.SysExamPaperAnswer;
import com.ruoyi.system.domain.wx.SchoolStatisticsVo;
import com.ruoyi.system.service.ISysExamPaperAnswerService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Comparator;
import java.util.function.Function;
import java.text.DecimalFormat;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.core.domain.entity.SysDictData;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;

/**
 * 试卷答案Controller
 *
 * @author ruoyi
 * @date 2025-09-18
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/system/answer")
public class SysExamPaperAnswerController extends BaseController {

    private final ISysExamPaperAnswerService sysExamPaperAnswerService;

    @PreAuthorize("@ss.hasPermi('system:answer:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysExamPaperAnswer sysExamPaperAnswer) {
        startPage();
        List<SysExamPaperAnswer> list = sysExamPaperAnswerService.selectSysExamPaperAnswerList(sysExamPaperAnswer);
        return getDataTable(list);
    }

    @PreAuthorize("@ss.hasPermi('system:answer:export')")
    @Log(title = "试卷答案", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, SysExamPaperAnswer sysExamPaperAnswer) {
        List<SysExamPaperAnswer> list = sysExamPaperAnswerService.selectSysExamPaperAnswerList(sysExamPaperAnswer);
        ExcelUtil<SysExamPaperAnswer> util = new ExcelUtil<SysExamPaperAnswer>(SysExamPaperAnswer.class);
        util.exportExcel(response, list, "试卷答案数据");
    }

    @PreAuthorize("@ss.hasPermi('system:answer:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(sysExamPaperAnswerService.getById(id));
    }

    @PreAuthorize("@ss.hasPermi('system:answer:add')")
    @Log(title = "试卷答案", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysExamPaperAnswer sysExamPaperAnswer) {
        return toAjax(sysExamPaperAnswerService.save(sysExamPaperAnswer));
    }

    @PreAuthorize("@ss.hasPermi('system:answer:edit')")
    @Log(title = "试卷答案", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody SysExamPaperAnswer sysExamPaperAnswer) {
        return toAjax(sysExamPaperAnswerService.updateById(sysExamPaperAnswer));
    }

    @PreAuthorize("@ss.hasPermi('system:answer:remove')")
    @Log(title = "试卷答案", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(sysExamPaperAnswerService.removeBatchByIds(Arrays.asList(ids)));
    }

    @Anonymous
    @PostMapping(value = "/submit")
    public AjaxResult submit(@Validated @RequestBody ExamPaperAnswerObject examPaperAnswerObject) {
        return toAjax(sysExamPaperAnswerService.submit(examPaperAnswerObject));
    }

    @Anonymous
    @PostMapping(value = "/whether/submit")
    public AjaxResult whetherSubmit(@Validated @RequestBody ExamPaperAnswerObject examPaperAnswerObject) {
        return toAjax(sysExamPaperAnswerService.whetherSubmit(examPaperAnswerObject));
    }


    // 查询试卷的题目分类统计情况

    @GetMapping(value = "/getExamPaperTypeStatistics/{examPaperId}")
    public AjaxResult getExamPaperTypeStatistics(@PathVariable Long examPaperId) {
        return success(sysExamPaperAnswerService.getExamPaperTypeStatistics(examPaperId));
    }


    @GetMapping(value = "/getExamPaperTypeStatistics")
    public AjaxResult getExamPaperTypeStatistics(ExamPaperAnswerObject examPaperAnswerObject) {
        return success(sysExamPaperAnswerService.getExamPaperTypeStatistics(examPaperAnswerObject));
    }


    // 查询报名信息
    @PreAuthorize("@ss.hasPermi('system:answer:list')")
    @GetMapping("/statistics/list")
    public TableDataInfo statisticsList(SysExamPaperAnswer sysExamPaperAnswer) {
        // 先查出所有数据
        List<SysExamPaperAnswer> list = sysExamPaperAnswerService.statisticsList(sysExamPaperAnswer);
        // 读取分页参数并在内存中分页
        PageDomain pageDomain = TableSupport.buildPageRequest();
        int pageNum = pageDomain.getPageNum() != null ? pageDomain.getPageNum() : 1;
        int pageSize = pageDomain.getPageSize() != null ? pageDomain.getPageSize() : 10;
        int total = list.size();
        int fromIndex = Math.max((pageNum - 1) * pageSize, 0);
        int toIndex = Math.min(fromIndex + pageSize, total);
        List<SysExamPaperAnswer> pageList = fromIndex >= total ? new ArrayList<>() : list.subList(fromIndex, toIndex);
        // 组装分页响应对象（总数为全部数据量，rows为当前页数据）
        TableDataInfo rspData = new TableDataInfo(pageList, total);
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        return rspData;
    }


    // 查询报名信息
    @PreAuthorize("@ss.hasPermi('system:answer:list')")
    @GetMapping("/statistics/school/list")
    public TableDataInfo statisticsSchoolList(SysExamPaperAnswer sysExamPaperAnswer) {
        // 先查出所有数据
        List<SchoolStatisticsVo> list = sysExamPaperAnswerService.statisticsSchoolList(sysExamPaperAnswer);
        // 读取分页参数并在内存中分页
        PageDomain pageDomain = TableSupport.buildPageRequest();
        int pageNum = pageDomain.getPageNum() != null ? pageDomain.getPageNum() : 1;
        int pageSize = pageDomain.getPageSize() != null ? pageDomain.getPageSize() : 10;
        int total = list.size();
        int fromIndex = Math.max((pageNum - 1) * pageSize, 0);
        int toIndex = Math.min(fromIndex + pageSize, total);
        List<SchoolStatisticsVo> pageList = fromIndex >= total ? new ArrayList<>() : list.subList(fromIndex, toIndex);
        // 组装分页响应对象（总数为全部数据量，rows为当前页数据）
        TableDataInfo rspData = new TableDataInfo(pageList, total);
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        return rspData;
    }

    /**
     * 导出试卷答案统计列表（列与页面 el-table 一致）
     */
    @PreAuthorize("@ss.hasPermi('system:answer:export')")
    @Log(title = "试卷答案统计", businessType = BusinessType.EXPORT)
    @PostMapping("/statistics/export")
    public void statisticsExport(HttpServletResponse response, SysExamPaperAnswer sysExamPaperAnswer) {
        // 查询统计列表数据（不分页）
        List<SysExamPaperAnswer> list = sysExamPaperAnswerService.statisticsList(sysExamPaperAnswer);

        // 统计中所有出现过的分类名称，按字典排序（若无字典序则按名称）
        Set<String> allClassificationNames = list.stream()
            .flatMap(a -> Optional.ofNullable(a.getClassificationStatistics()).orElse(new ArrayList<>()).stream())
            .map(com.ruoyi.system.domain.wx.PaperTypeStatisticsVo::getName)
            .filter(Objects::nonNull)
            .collect(Collectors.toCollection(LinkedHashSet::new));

        List<SysDictData> dictList = Optional.ofNullable(DictUtils.getDictCache("question_classification")).orElse(new ArrayList<>());
        Map<String, Long> dictSortMap = dictList.stream()
            .collect(Collectors.toMap(SysDictData::getDictLabel, d -> Optional.ofNullable(d.getDictSort()).orElse(Long.MAX_VALUE), (a, b) -> a));
        List<String> classificationHeaders = allClassificationNames.stream()
            .sorted(Comparator.comparingLong(name -> dictSortMap.getOrDefault(name, Long.MAX_VALUE)))
            .collect(Collectors.toList());

        // 构建 Excel
        Workbook wb = new SXSSFWorkbook(100);
        Sheet sheet = wb.createSheet("试卷答案统计数据");
        int rowIdx = 0;
        Row header = sheet.createRow(rowIdx++);
        int col = 0;
        header.createCell(col++).setCellValue("用户姓名");
        header.createCell(col++).setCellValue("试卷名称");
        header.createCell(col++).setCellValue("学校名称");
        header.createCell(col++).setCellValue("联系方式");
        header.createCell(col++).setCellValue("系统得分");
        header.createCell(col++).setCellValue("试卷题数");
        for (String c : classificationHeaders) {
            header.createCell(col++).setCellValue(c + "[总得分/题目数量/平均分/定级标准]");
        }
        header.createCell(col++).setCellValue("综合定级");

        DecimalFormat df = new DecimalFormat("0.00");
        for (SysExamPaperAnswer a : list) {
            Row row = sheet.createRow(rowIdx++);
            int i = 0;
            row.createCell(i++).setCellValue(a.getName() == null ? "" : a.getName());
            row.createCell(i++).setCellValue(a.getTitle() == null ? "" : a.getTitle());
            row.createCell(i++).setCellValue(a.getSchool() == null ? "" : a.getSchool());
            row.createCell(i++).setCellValue(a.getPhone() == null ? "" : a.getPhone());
            row.createCell(i++).setCellValue(a.getScore() == null ? 0 : a.getScore());
            row.createCell(i++).setCellValue(a.getQuestionCount() == null ? 0 : a.getQuestionCount());

            Map<String, com.ruoyi.system.domain.wx.PaperTypeStatisticsVo> statMap = Optional.ofNullable(a.getClassificationStatistics()).orElse(new ArrayList<>())
                .stream().collect(Collectors.toMap(com.ruoyi.system.domain.wx.PaperTypeStatisticsVo::getName, Function.identity(), (x, y) -> x));

            int totalPoints = 0;
            for (String c : classificationHeaders) {
                com.ruoyi.system.domain.wx.PaperTypeStatisticsVo vo = statMap.get(c);
                String valStr;
                String gradeStr;
                if (vo != null) {
                    long cnt = vo.getCount() == null ? 0L : vo.getCount();
                    long total = vo.getTotalScore() == null ? 0L : vo.getTotalScore();
                    String avg = cnt > 0 ? df.format((double) total / (double) cnt) : "0.00";
                    gradeStr = getGrade(c, total);
                    valStr = total + "/" + cnt + "/" + avg + "/" + gradeStr;
                    totalPoints += gradeToPoints(gradeStr);
                } else {
                    gradeStr = "【良好】";
                    valStr = "0/0/0.00/" + gradeStr;
                    totalPoints += gradeToPoints(gradeStr);
                }
                row.createCell(i++).setCellValue(valStr);
            }
            // 综合定级列
            row.createCell(i++).setCellValue(toOverallGrade(totalPoints));
        }

        try {
            String filename = URLEncoder.encode("试卷答案统计数据.xlsx", StandardCharsets.UTF_8.name());
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + filename);
            wb.write(response.getOutputStream());
        } catch (Exception e) {
            // ignore
        } finally {
            IOUtils.closeQuietly(wb);
        }
    }

    // 分类定级：按分类名称与总分判断
    private String getGrade(String name, long totalScore) {
        String n = name == null ? "" : name.trim();
        long s = totalScore;

        if (n.contains("人格态度")) {
            if (s >= 5) return "【重点关注】";
            if (s == 4) return "【中度关注】";
            if (s == 3) return "【轻微关注】";
            return "【良好】";
        }
        if (n.contains("情绪与心理状态")) {
            if (s >= 88) return "【重点关注】";
            if (s >= 66) return "【中度关注】";
            if (s >= 44) return "【轻微关注】";
            return "【良好】";
        }
        if (n.contains("睡眠质量")) {
            if (s >= 18) return "【重点关注】";
            if (s >= 12) return "【中度关注】";
            if (s >= 6) return "【轻微关注】";
            return "【良好】";
        }
        if (n.contains("生活态度与风险筛查")) {
            if (s >= 12) return "【重点关注】";
            if (s >= 9) return "【中度关注】";
            if (s >= 7) return "【轻微关注】";
            return "【良好】";
        }
        if (n.contains("感恩")) {
            if (s <= 6) return "【重点关注】";
            if (s <= 10) return "【中度关注】";
            if (s <= 14) return "【轻微关注】";
            return "【良好】";
        }
        if (n.contains("自我效能") || n.contains("乐观") || n.contains("工作韧性") || n.contains("韧性")) {
            if (s <= 20) return "【重点关注】";
            if (s <= 33) return "【中度关注】";
            if (s <= 45) return "【轻微关注】";
            return "【良好】";
        }
        if (n.contains("抗压能力")) {
            if (s <= 5) return "【重点关注】";
            if (s <= 8) return "【中度关注】";
            if (s <= 11) return "【轻微关注】";
            return "【良好】";
        }
        if (n.contains("社会支持")) {
            if (s <= 24) return "【重点关注】";
            if (s <= 36) return "【中度关注】";
            if (s <= 48) return "【轻微关注】";
            return "【良好】";
        }
        if (n.contains("职业倦怠") || n.contains("满意度")) {
            if (s <= 30) return "【重点关注】";
            if (s <= 50) return "【中度关注】";
            if (s <= 60) return "【轻微关注】";
            return "【良好】";
        }
        return "【未设定】";
    }

    // 定级折算积分
    private int gradeToPoints(String grade) {
        if ("【重点关注】".equals(grade)) return 12;
        if ("【中度关注】".equals(grade)) return 6;
        if ("【轻微关注】".equals(grade)) return 3;
        return 0;
    }

    // 综合定级阈值判定
    private String toOverallGrade(int total) {
        if (total >= 72) return "【重点关注】";
        if (total >= 42) return "【中度关注】";
        if (total >= 15) return "【轻微关注】";
        return "【良好】";
    }
}
